package UI;// GLFWWindow.java (渲染窗口封装)

import DataStructure.Model;
import OBJ.*;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30C;

import java.awt.*;
import java.io.IOException;
import java.util.concurrent.ConcurrentLinkedQueue;

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.opengl.GL20C.*;

public class VoxelWindow {

    // 着色器
    VoxelShaderProgram shader = null ;                                              // 着色器程序

    private Matrix4f view;                                              //视图
    private Matrix4f projection;                                        //投影
    //模型
    public String modelPath;            // 模型路径
    public String name;
    Model model;                        // 模型
    VoxelRenderer voxelRenderer;        // 模型渲染器
    VoxelLoader voxelLoader;            // 体素加载器
    int heightLimit;
    //更新队列
    ConcurrentLinkedQueue<MaterialUpdateRequest> materialQueue;

    // 窗口
    private long windowHandle;                          // 窗口句柄
    private int width;                                  // 窗口宽度
    private int height;                                 // 窗口高度

    // 旋转和移动
    boolean isRotating = false;                         // 是否正在旋转
    boolean isMoving = false;                           // 是否正在移动
    double lastX = 0;                                   // 上一次鼠标位置
    double lastY = 0;                                   // 上一次鼠标位置
    private float scale = 1.0f;                         // 缩放
    private final Vector3f translation = new Vector3f();// 平移
    private float rotationY = 0.0f;                     // 旋转

    //构造函数
    public VoxelWindow(int width, int height, String modelPath, String name, ConcurrentLinkedQueue<MaterialUpdateRequest> materialQueue,int heightLimit) {
        this.width = width;
        this.height = height;
        this.modelPath = modelPath;
        this.name = name;
        this.materialQueue = materialQueue;
        this.heightLimit = heightLimit;
    }
    //运行
    public void run() throws IOException {
        initGLFW(); // 初始化GLFW
        initGL();   // 初始化OpenGL
        mainLoop(); // 主循环
        cleanup();  // 清理资源
    }
    //初始化GLFW
    private void initGLFW() {
        if (!glfwInit()) {
            throw new IllegalStateException("Unable to initialize GLFW");
        }
        // 配置GLFW
        windowHandle = glfwCreateWindow(width, height, "Voxel Renderer", 0, 0);// 创建窗口
        glfwMakeContextCurrent(windowHandle); // 设置当前上下文
        glfwSetWindowAspectRatio(windowHandle, width, height);  // 限定窗口长宽比为初始化时的长宽比
        glfwSwapInterval(1); // 垂直同步
        // 设置回调
        glfwSetScrollCallback(windowHandle, this::handleScroll);// 滚轮回调
        glfwSetMouseButtonCallback(windowHandle, this::handleMouseButton);// 鼠标按键回调
        glfwSetFramebufferSizeCallback(windowHandle, this::framebuffer_size_callback);// 窗口大小改变回调
    }
    //初始化OpenGL
    private void initGL() {
        GL.createCapabilities(); // 创建OpenGL上下文
        glEnable(GL_DEPTH_TEST); // 启用深度测试
        glfwShowWindow(windowHandle); // 显示窗口
    }
    //主循环
    private void mainLoop() throws IOException {
        render();   // 初始化模型、着色器、摄像机
        while(!glfwWindowShouldClose(windowHandle) && !Thread.currentThread().isInterrupted() )// 窗口未关闭且线程未中断
        {
            // 渲染指令
            renderFrame();
            // 检查并调用事件，交换缓冲
            glfwPollEvents();
            glfwSwapBuffers(windowHandle);
        }
        // 终止前释放资源
        glfwDestroyWindow(windowHandle);
        glfwTerminate();
    }

    private void render() throws IOException {
        // 清空颜色缓冲区和深度缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        shader = new VoxelShaderProgram(FileUtils.loadResource("vertex_voxel.glsl"),FileUtils.loadResource("fragment_voxel.glsl"));

        shader.use();
        // 加载模型
        model  = ObjModelLoader.loadModel(modelPath+"\\",name);
        ObjModelLoader.loadMtl(modelPath+"\\",name,model);
        voxelRenderer = new VoxelRenderer();
        // 加载体素
        voxelLoader = new VoxelLoader(model);
        voxelLoader.loadVoxel(heightLimit);

        // 设置摄像机参数
        Vector3f cameraPos = new Vector3f(0, 0, 3);
        Vector3f cameraTarget = new Vector3f(0, 0, 0);
        Vector3f cameraUp = new Vector3f(0, 1, 0);



        int[] width = new int[1], height = new int[1];
        glfwGetWindowSize(windowHandle, width, height);
        projection = new Matrix4f().perspective(
                (float) Math.toRadians(45.0f),
                (float) width[0] / height[0], // 动态宽高比
                0.1f,
                100.0f
        );
        view = new Matrix4f().lookAt(cameraPos, cameraTarget, cameraUp);
    }

    private void renderFrame() throws IOException {
        processInput(); // 处理输入
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        shader.use();
        //更新摄像机位置
        double xpos[] = new double[1];
        double ypos[] = new double[1];
        glfwGetCursorPos(windowHandle, xpos, ypos);
        double xoffset = xpos[0] ;
        double yoffset = ypos[0] ;
        if(isMoving || isRotating) {
            xoffset = xpos[0] - lastX;
            yoffset = ypos[0] - lastY;
        }
        lastX = xpos[0];
        lastY = ypos[0];
        if (isRotating) {
            // 根据xoffset来计算旋转角度
            rotationY += (float) (xoffset * 0.01f);
        }
        if (isMoving) {
            // 根据xoffset和yoffset来计算移动量
            transL(xoffset*1.75, yoffset*1.75);
        }
        // 更新变换矩阵
//        Vector3f cameraPos = new Vector3f(0, 0, 3).add(translation);
//        Vector3f cameraTarget = new Vector3f(0, 0, 0).add(translation);
//        view = new Matrix4f().lookAt(
//                cameraPos,
//                cameraTarget,
//                new Vector3f(0, 1, 0)
//        ).rotateY(rotationY);
//
        shader.setMat4("view", view);
//
//        int[] width = new int[1], height = new int[1];
//        glfwGetWindowSize(windowHandle, width, height);
//        projection = new Matrix4f().perspective(
//                (float) Math.toRadians(45.0f),
//                (float) width[0] / height[0],
//                0.1f,
//                100.0f
//        );
        shader.setMat4("projection", projection); // 每帧更新


        Matrix4f modelMatrix = new Matrix4f()
                .translate(translation)
                .rotateY(rotationY)
                .scale(scale);

        shader.setMat4("model", modelMatrix);


        // 上传矩阵到着色器
        int viewLoc = glGetUniformLocation(shader.programId, "view");
        int projLoc = glGetUniformLocation(shader.programId, "projection");

        glUniformMatrix4fv(viewLoc, false, view.get(new float[16]));
        glUniformMatrix4fv(projLoc, false, projection.get(new float[16]));

        // 遍历体素
        for (int x = 0; x < voxelLoader.voxelLength; x++) {
            for (int y = 0; y < voxelLoader.voxelHeight; y++) {
                for (int z = 0; z < voxelLoader.voxelWidth; z++) {

                    if (voxelLoader.voxelGrid[x][y][z] == 1) {
                        // 计算体素位置
                        float posX = voxelLoader.boxMin.x + x * voxelLoader.voxelSize;
                        float posY = voxelLoader.boxMin.y + y * voxelLoader.voxelSize;
                        float posZ = voxelLoader.boxMin.z + z * voxelLoader.voxelSize;

                        // 设置模型矩阵
                        Matrix4f model = new Matrix4f()
                                .translate(posX + voxelLoader.voxelSize / 2,
                                        posY + voxelLoader.voxelSize / 2,
                                        posZ + voxelLoader.voxelSize / 2)
                                .scale(voxelLoader.voxelSize);
                        Matrix4f globalTransform = new Matrix4f()
                                .translate(translation)
                                .rotateY(rotationY)
                                .scale(scale);

                        // 上传模型矩阵和颜色
                        int modelLoc = glGetUniformLocation(shader.programId, "model");
                        Matrix4f finalModel = globalTransform.mul(model); // 矩阵相乘顺序很重要
                        //glUniformMatrix4fv(modelLoc, false, finalModel.get(new float[16]));
                        shader.setMat4("model",finalModel);

                        Color color = voxelLoader.voxelColor[x][y][z];
                        glUniform3f(glGetUniformLocation(shader.programId, "color"),
                                color.getRed() / 255.0f,
                                color.getGreen() / 255.0f,
                                color.getBlue() / 255.0f);

                        // 绘制立方体
                        GL30C.glBindVertexArray(voxelRenderer.vao);
                        glEnableVertexAttribArray(0); // 确保位置属性启用
                        glDrawArrays(GL_TRIANGLES, 0, 36); // 假设立方体有36个顶点（12个三角形）
                    }
                }
            }
        }

        //绘制包围盒
        //printBox();



    }

    // 平移
    private void transL(double deltaX, double deltaY) {
        int[] width = new int[1];
        int[] height = new int[1];
        glfwGetWindowSize(windowHandle, width, height);

        int viewportWidth = width[0];
        int viewportHeight = height[0];

        if (deltaX != 0 || deltaY != 0) {
            float deltaNdcX = (float) (2.0f * deltaX / viewportWidth);
            float deltaNdcY = (float) (-2.0f * deltaY / viewportHeight);
            Vector4f ray_eye = new Vector4f(deltaNdcX, deltaNdcY, 0.0f, 0.0f);
            Matrix4f inverseProjection = new Matrix4f(projection).invert();
            Vector4f ray_clip = new Vector4f();
            inverseProjection.transform(ray_eye, ray_clip);
            Matrix4f inverseView = new Matrix4f(view).invert();
            Vector4f ray_world = new Vector4f();
            inverseView.transform(ray_clip, ray_world);
            translation.add(ray_world.x(), ray_world.y(), 0);
        }
    }

    //重置变换
    public void resetTransform() {
        scale = 1.0f;
        translation.set(0, 0, 0);
        rotationY = 0.0f;
    }


    private void printBox(){
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.minY, voxelLoader.maxZ);
        GL11.glEnd();
        GL11.glBegin(GL_LINE_LOOP);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.minZ);
        GL11.glVertex3f(voxelLoader.maxX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glVertex3f(voxelLoader.minX, voxelLoader.maxY, voxelLoader.maxZ);
        GL11.glEnd();
    }


    // 输入处理回调
    private void handleScroll(long window, double xoffset, double yoffset) {
        scale += yoffset * 0.1f;
        scale = Math.max(0.1f, scale);
    }
    private void handleMouseButton(long window, int button, int action, int mods) {
        if (action == GLFW_PRESS) {
            if (button == GLFW_MOUSE_BUTTON_RIGHT) {
                // 右键按下，开始旋转
                isRotating = true;
            } else if (button == GLFW_MOUSE_BUTTON_LEFT) {
                // 左键按下，开始移动
                isMoving = true;
            }
        } else if (action == GLFW_RELEASE) {
            if (button == GLFW_MOUSE_BUTTON_RIGHT) {
                // 右键释放，停止旋转
                isRotating = false;
            } else if (button == GLFW_MOUSE_BUTTON_LEFT) {
                // 左键释放，停止移动
                isMoving = false;
            }
        }
    }
    //窗口大小改变回调
    void framebuffer_size_callback(long windowHandle, int width, int height)
    {
        //保持视口不变
        glViewport(0, 0, width, height);
    }

    //esc退出等
    private void processInput() {
        if (glfwGetKey(windowHandle, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
            glfwSetWindowShouldClose(windowHandle, true);
        }
    }
    //清理
    public void cleanup() {
        glfwDestroyWindow(windowHandle);
        glfwTerminate();
    }
}